;; https://projecteuler.net/problem=22

;; Names scores

;; Problem 22

;; Using names.txt (right click and 'Save Link/Target As...'), a 46K
;; text file containing over five-thousand first names, begin by
;; sorting it into alphabetical order. Then working out the
;; alphabetical value for each name, multiply this value by its
;; alphabetical position in the list to obtain a name score.

;; For example, when the list is sorted into alphabetical order,
;; COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name
;; in the list. So, COLIN would obtain a score of 938 × 53 = 49714.

;; What is the total of all the name scores in the file?


(import
 (except (rnrs base) let-values map)
 (only (guile) lambda* λ)
 (srfi srfi-1)
 (lib fileio)
 (contract)
 (prefix (lib math) math:))


(define-with-contract read-names
  (require (string? file-name))
  (ensure (list? <?>)
          (not (null? <?>)))
  (λ (file-name)
    (let* ([file-content
            (get-string-from-file
             (string-join (list (dirname (current-filename)) "names.txt")
                          "/"))])
      (map
       (λ (name-with-quotes)
         (string-trim-both name-with-quotes
                           (λ (char) (char=? char #\"))))
       (string-split file-content
                     (λ (char)
                       (char=? char #\,)))))))


(define-with-contract letter-score
  (require (char? letter))
  (ensure (integer? <?>)
          (positive? <?>))
  (λ (letter)
    (+ (- (char->integer letter)
          (char->integer #\A))
       1)))


(define-with-contract name-score
  (require (string? name))
  (ensure (integer? <?>)
          (positive? <?>))
  (λ (name)
    (math:sum (map letter-score (string->list name)))))


(let* ([file-name (second (command-line))]
       [sorted-names (sort (read-names file-name)
                           string-ci<)])
  (let iter ([index 0]
             [remaining-names sorted-names]
             [sum 0])
    (cond
     [(null? remaining-names) sum]
     [else
      (iter (+ index 1)
            (cdr remaining-names)
            (+ sum (* (name-score (first remaining-names))
                      (+ index 1))))]))
  (display
   (simple-format
    #f "~s\n"
    (let iter ([index 0]
               [remaining-names sorted-names]
               [sum 0])
      (cond
       [(null? remaining-names) sum]
       [else
        (iter (+ index 1)
              (cdr remaining-names)
              (+ sum (* (name-score (first remaining-names))
                        (+ index 1))))])))))
